#ifndef NODE_H
#define NODE_H

#include "bga/system/Scoped_Ptr.h"
#include "bga/system/NodeBase.h"
#include <list>

/**
 * \namespace bga
 * \brief API namespace
 */
namespace bga
{

class NodeListener;

template< typename T >
class Tree;

template< typename T >
class DepthFirstTreeIterator;


/*!
 * \class Node
 * \brief A node in a tree
 *
 * This class handle for all Nodes which could be contained in a tree
 */
template< typename T >
class Node : public NodeBase
{
    friend class Tree<T>;
    friend class DepthFirstTreeIterator<T>;

	protected:
        /**!
		 * \brief Contructor
		 * \param parent : the parent of current node being constructed
		 */
		Node(Node<T>* parent = NULL);

    public:
        // DEBUG
        std::string name;     ///!< Name of the node

        /**
         * Destructor
         */
        virtual ~Node();

        /**
         * \brief add a child to the current Node
         * \param node : node to add
         */
		void addChild(Node<T>* node);

        /// TEMP, a passer en iterator ou faire plus propre
        void resetChildrenIterator() { childrenIterator = childrenList.begin(); }
        Node<T>* getNextChildren()
        {
            if (childrenIterator != childrenList.end())
            {
                return (*childrenIterator++).get();
            }
            return NULL;
        }

		/**!
		 * \brief get the parent of the current Node
		 * \return the parent of the current node
		 */
        Node<T>* getParent() const;

		/**!
		 * \brief get the element of the current Node
		 * \return the element of the current node
		 */
        T* getElement() const;

		/**!
		 * \brief set the element of the current Node
		 * \param element : the element of the current node
		 */
		void setElement(T& element);

        /**!
		 * \brief get the left child of the current Node
		 * \return the left child of the current node
		 */
        //Node<T>* getLeftChild() const;

		/**!
		 * \brief get the right child of the current Node
		 * \return the right child of the current node
		 */
		//Node<T>* getRightChild() const;

        /**!
         * \brief create a Node
         * \return Node created
         *
         * This method creates a Node. Be careful, to delete it, you have to call destroyNode().
         * If you add this node to a tree or a graph, you don't have to take care of the destruction.
         */
		virtual Node<T>* createNode();

		/**!
         * \brief delete a Node
         * \param Node to destroy
         *
         * This method deletes a Node created with createNode()
         */
		virtual void destroyNode(Node<T>* node);

        /*!
         * \brief add a new node listener to the current node
         * \param listener : new node listener to add
         * \param herits : if true, then the listener will be add all children of the current node
         *
         * Add a new listener to handle nodes add and removal
         */
		void addNodeListener(bga::NodeListener& nodeListener, bool herits = true);

	protected:
        Node<T>* parent;    ///!< Parent of the current node

        /*Scoped_Ptr< Node<T> > leftNode;   ///!< Left child of the current node
        Scoped_Ptr< Node<T> > rightNode;  ///!< Right child of the current node*/
        std::list< Scoped_Ptr< Node<T> > > childrenList;   ///!< List of Nodes children

        /// TEMP
        typename std::list< Scoped_Ptr< Node<T> > >::iterator childrenIterator;

        T* element;   ///!< Element stored int the node

        /*!
         * \brief Function the handle a node adding
         *
         * This function is called when we add an object to the current node. It creates the NodeEvent associated and called
         * the matching function of the matching listener
         */
        void handleNodeAddedEvent();

        /*!
         * \brief Function the handle a node removal
         *
         * This function is called when we remove an object to the current node. It creates the NodeEvent associated and called
         * the matching function of the matching listener
         */
        void handleNodeRemovedEvent();

        /*!
         * \brief Function the handle a node modification
         *
         * This function is called when we modify an object to the current node. It creates the NodeEvent associated and called
         * the matching function of the matching listener
         */
        void handleNodeModifiedEvent();

         /*!
         * \brief Function the handle when it is processed
         *
         * This function is called when the node is processed. It creates the NodeEvent associated and called
         * the matching function of the matching listener
         */
        void handleNodeProcessedEvent();

	private:
        std::list< bga::NodeListener* > nodeListeners;  ///!< Contains all the node Listeners

};

}

#include "bga/system/Node.inl"

#endif // NODE_H

